﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
using System.Diagnostics;

namespace AssistCore
{
    public class TencentImageCore
    {
        private string AppID { get; set; }
        private string SecretID { get; set; }
        private string SecretKey { get; set; }

        private readonly string fileKeyName = "image";
        private readonly string requestUrl = "http://recognition.image.myqcloud.com/ocr/general";

        public TencentImageCore(string appId, string secretId, string secretKey)
        {
            this.AppID = appId;
            this.SecretID = secretId;
            this.SecretKey = secretKey;
        }
        public dynamic OCRGeneral(string fileName)
        {
            Stopwatch sw = new Stopwatch();
            NameValueCollection val = new NameValueCollection();
            val.Add("appid", this.AppID);
            sw.Start();
            var ret = HttpPostData(fileName, val);
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            sw.Restart();
            var ret2= JsonConvert.DeserializeObject<dynamic>(ret);
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            return ret2;
        }
        private string HttpPostData(string fileName, NameValueCollection stringDict)
        {
            var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            return HttpPostData(fileStream, fileName, stringDict);
        }

        private string HttpPostData(Stream fileStream,string fileName, NameValueCollection stringDict)
        {
            string responseContent;
            var memStream = new MemoryStream();
            var webRequest = (HttpWebRequest)WebRequest.Create(requestUrl);
            // 边界符
            var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
            // 边界符
            var beginBoundary = Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
            // 最后的结束符
            var endBoundary = Encoding.ASCII.GetBytes("--" + boundary + "--\r\n");
            // 设置属性
            webRequest.Method = "POST";
            webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
            webRequest.ContentLength = fileStream.Length;
            webRequest.Host = "recognition.image.myqcloud.com";
            webRequest.Headers.Add("authorization", this.GetSign(fileName));
            // 写入文件
            const string filePartHeader =
                "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
                 "Content-Type: application/octet-stream\r\n\r\n";
            var header = string.Format(filePartHeader, fileKeyName, fileName);
            var headerbytes = Encoding.UTF8.GetBytes(header);
            memStream.Write(beginBoundary, 0, beginBoundary.Length);
            memStream.Write(headerbytes, 0, headerbytes.Length);
            var buffer = new byte[1024];
            int bytesRead; // =0
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                memStream.Write(buffer, 0, bytesRead);
            }
            // 写入字符串的Key
            var stringKeyHeader = "\r\n--" + boundary +
                                   "\r\nContent-Disposition: form-data; name=\"{0}\"" +
                                   "\r\n\r\n{1}\r\n";
            foreach (byte[] formitembytes in from string key in stringDict.Keys
                                             select string.Format(stringKeyHeader, key, stringDict[key])
                                                 into formitem
                                             select Encoding.UTF8.GetBytes(formitem))
            {
                memStream.Write(formitembytes, 0, formitembytes.Length);
            }
            // 写入最后的结束边界符
            memStream.Write(endBoundary, 0, endBoundary.Length);
            webRequest.ContentLength = memStream.Length;
            var requestStream = webRequest.GetRequestStream();
            memStream.Position = 0;
            var tempBuffer = new byte[memStream.Length];
            memStream.Read(tempBuffer, 0, tempBuffer.Length);
            memStream.Close();
            requestStream.Write(tempBuffer, 0, tempBuffer.Length);
            requestStream.Close();
            var httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
            using (var httpStreamReader = new StreamReader(httpWebResponse.GetResponseStream(),
                                                            Encoding.GetEncoding("utf-8")))
            {
                responseContent = httpStreamReader.ReadToEnd();
            }
            fileStream.Close();
            httpWebResponse.Close();
            webRequest.Abort();
            return responseContent;
        }

        /// <summary>
        /// 获取签名
        /// </summary>
        public string GetSign(string filePath)
        {
            var appId = this.AppID;//开发者的 APPID，接入智能图像时由系统生成
            var bucket = "";//Bucket，空间名称，即图片资源的组织管理单元
            var secretId = this.SecretID;//Secret ID
            var secretKey = this.SecretKey;//secretKey
            var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            var currentTime = Convert.ToInt64(ts.TotalSeconds);//当前时间戳，是一个符合 UNIX Epoch 时间戳规范的数值，单位为秒，多次签名时，e 应大于 t
            var expiredTime = Convert.ToInt64((DateTime.UtcNow.AddMinutes(180) - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds);//签名的有效期，是一个符合 UNIX Epoch 时间戳规范的数值，单位为秒；单次签名时，e 必须设置为 0
            var rand = new Random().Next(10000, 999999999);//随机串，无符号 10 进制整数，用户需自行生成，最长 10 位
            var userid = 0;//历史遗留字段，请填写为 0
            var fileid = Path.GetFileName(filePath);//资源存储的唯一标识，单次签名必填；多次签名选填，如填写则会验证与当前操作的文件路径是否一致。
            var encryptText = $"a={appId}&b={bucket}&k={secretId}&e={expiredTime}&t={currentTime}&r={rand}&u={userid}&f={fileid}";
            var sign = Hmacsha1Encrypt(encryptText, secretKey);
            return sign;
        }
        /// <summary>
        /// HMACSHA1算法加密
        /// </summary>
        private static string Hmacsha1Encrypt(string encryptText, string encryptKey)
        {
            using (HMACSHA1 mac = new HMACSHA1(Encoding.UTF8.GetBytes(encryptKey)))
            {
                var hash = mac.ComputeHash(Encoding.UTF8.GetBytes(encryptText));
                var pText = Encoding.UTF8.GetBytes(encryptText);
                var all = new byte[hash.Length + pText.Length];
                Array.Copy(hash, 0, all, 0, hash.Length);
                Array.Copy(pText, 0, all, hash.Length, pText.Length);
                return Convert.ToBase64String(all);
            }
        }
    }
}
